#ifndef RENDERAREA_H
#define RENDERAREA_H

#include <QWidget>
#include <QPen>
#include <QPainter>
#include <Qvector>
#include <random>
#include <ctime>
#include <vector>
#include <iostream>
#include <QDebug>
#include <QMouseEvent>
#include <QLabel>
#include <QMenu>
#include <QtMath>
#include <queue>
#include <algorithm>
#include <cmath>
struct Edge{
    int to;
    int weight;
};

namespace Ui {
class RenderArea;
}
class RenderArea;
namespace Utils{
void buildLineMenu(RenderArea* renderArea,const QPoint& pos,int line_index);
void buildPointMenu(RenderArea* renderArea,const QPoint& pos,int point_index);
void buildNormalMenu(RenderArea* renderArea,const QPoint& pos);
int findPointIndex(const QVector<QPoint>& points, const QPoint& target);
bool isPointOnLine(const QLineF &line, const QPointF &point, double tolerance=1.0);
int getIdxOfLine(const RenderArea& renderArea,const QPoint& pos);
int getIdxOfRandomPointInRect(const RenderArea& renderArea,const QPoint& pos);
void addPoint(RenderArea* renderArea,int x,int y);
void buildDjGraph(RenderArea* renderArea);
std::vector<int> buildPath(const std::vector<int>& prev, int end);
int euclideanDistanceSquared(QPoint p1,QPoint p2);
};
class RenderArea : public QWidget
{
    Q_OBJECT

public:
    explicit RenderArea(QWidget *parent = nullptr);
    ~RenderArea();
public slots:
    void addRandomPoint();

private:
    Ui::RenderArea *ui;
    // 存放节点
    QVector<QPoint> point_list;
    // 存放路径
    QVector<QLine> line_list;
    // 上面这个路径不能用于迪节斯特拉，需要换用这个结构
    std::vector<std::vector<Edge>> dj_graph;
    // 最多点数量 默认成员初始化
    const int maxPointNum = 20;
    // 无向图
    std::vector<std::vector<int>> undirected_graph;
    int selectOne = -1;
    int selectTwo = -1;
    QPen pen;
    std::default_random_engine random_engine;  // 随机数引擎作为成员变量
    std::uniform_int_distribution<int> dist_x; // 分布对象也可以作为成员变量，但需要动态更新范围
    std::uniform_int_distribution<int> dist_y;
    // 关联label和point
    QHash<QPoint, QLabel*> pointLabelMap;

    // 导航相关
    // 起点only one -1,-1代表没有设定起点
    QPoint departure;
    // 终点only one -1,-1代表没设定终点
    QPoint destination;
    //  终点图标
    QPixmap destination_pixmap;
    //  起点图标
    QPixmap departure_pixmap;



    // 判断无向图两点之间是否存在连线
    bool isLineBetweenTwoPoint(int p1_index,int p2_index);
    // 清除selectOne selectTwo
    void clearSelectTwoPoint();
    // 设置无向图两点之间的状态
    void setUnDirectionGraphStateBetweenTwoPoint(int p1_index,int p2_index,int state);
    // 删除两个点之间的线
    void deleteLineBetweenTwoPoint(QPoint p1,QPoint p2);
    // 鼠标左键点击处理
    void handleLeftButtonClick(QMouseEvent* event);
    // 鼠标右键点击处理
    void handleRightButtonClick(QMouseEvent* event);

    // 用于debug，打印dj_graph
    void showDjGraph(){
        qDebug()<<"目前的dj_graph如下:";
        for(int i=0;i<dj_graph.size();i++){
            for(int j=0;j<dj_graph[i].size();j++){
                qDebug()<<"from:"<<i<<" to:"<<dj_graph[i][j].to<<" weight:"<<dj_graph[i][j].weight;

            }
        }
    }

    // 这里的友元似乎使用过度，未来需要考虑清楚什么场景下适合使用友元
    // 设计模式里面有一个vistor模式可以看看
    friend void Utils::addPoint(RenderArea* renderArea,int x,int y);
    friend void Utils::buildNormalMenu(RenderArea* renderArea,const QPoint& pos);
    friend void Utils::buildPointMenu(RenderArea* renderArea,const QPoint& pos,int point_index);
    friend void Utils::buildLineMenu(RenderArea* renderArea,const QPoint& pos,int line_index);
    friend int Utils::getIdxOfRandomPointInRect(const RenderArea& renderArea,const QPoint& pos);
    friend int Utils::getIdxOfLine(const RenderArea& renderArea,const QPoint& pos);
    friend void Utils::buildDjGraph(RenderArea* renderArea);
protected:

    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
};

#endif // RENDERAREA_H
